
# -*- coding: utf-8 -*-
"""
功能：从视频或音频文件根据时间轴文本批量分割音频片段
知识点：
1. 文件与目录操作（pathlib.Path）
2. 文本解析与正则表达式（re）
3. 数据处理（pandas.DataFrame）
4. 子进程调用外部命令（subprocess）
5. 第三方音视频处理库（ffmpy/ffmpeg）
扩展：可用于批量剪辑、自动化音频分割、数据清洗等场景
"""

import logging
import subprocess
import re
from pathlib import Path
import pandas as pd
from ffmpy import FFmpeg

# 日志设置，方便调试和错误追踪
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)


def get_media_duration(media_path):
    """
    获取视频或音频文件的总时长（秒）
    使用 ffprobe 命令行工具，需确保 ffmpeg/ffprobe 已安装并加入系统 PATH。
    """
    """
    获取媒体文件（音频/视频）的总时长（秒）
    """
    try:
        cmd = [
            'ffprobe',
            '-v', 'error',
            '-show_entries', 'format=duration',
            '-of', 'default=noprint_wrappers=1:nokey=1',
            str(media_path)
        ]
        duration = subprocess.check_output(cmd).strip()
        logger.info(f"媒体时长: {float(duration)} 秒")
        return float(duration)
    except subprocess.CalledProcessError as e:
        logger.error(f"获取媒体时长失败: {e}")
        return None


def split_media_by_timeline(media_file, timeline_txt, output_dir):
    """
    根据时间轴文本分割音频/视频文件
    参数：
        fp: 音频/视频文件路径
        csv_path: 时间轴文本路径（格式：【00:00:00】歌曲名）
        target_folder: 输出目录
    """
    media_path = Path(media_file)
    if not media_path.exists():
        logger.error(f"媒体文件不存在: {media_path}")
        return
    # 自动生成输出目录，默认为同名文件夹
    if not output_dir:
        output_dir = Path(media_path.parent, media_path.stem)
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    try:
        duration = get_media_duration(media_path)
        if duration is None:
            logger.error("未能获取有效的媒体时长")
            return

        # 解析时间轴文本，正则提取时间和片段名
        timeline_data = []
        with open(timeline_txt, encoding='utf8') as f:
            for line in f:
                line = line.strip()
                match = re.match(r'【(\d{2}:\d{2}:\d{2})】(.+)', line)
                if match:
                    start_time, segment_name = match.groups()
                    timeline_data.append({
                        "start_time": start_time,
                        "segment_name": segment_name.strip()
                    })
        if not timeline_data:
            logger.error(f"时间轴文本无有效内容: {timeline_txt}")
            return

        # 构建分割区间，最后一段结束时间为总时长
        df = pd.DataFrame(timeline_data)
        df['end_time'] = df['start_time'].shift(-1).fillna(duration)
        logger.info(f"分割区间：\n{df}")

        # 遍历分割，每段生成一个音频文件
        for idx, row in df.iterrows():
            segment_name = row['segment_name']
            start_time = row['start_time']
            end_time = row['end_time']
            output_path = output_dir / f"{segment_name}.aac"
            # ffmpeg命令行参数说明：-ss 起始时间，-to 结束时间，-vn 不处理视频，-acodec copy 直接拷贝音频流
            ff = FFmpeg(
                inputs={media_path: f'-ss {start_time} -to {end_time}'},
                outputs={output_path: f'-vn -acodec copy -y'})
            ff.run()
            logger.info(f"成功分割: {media_path} => {output_path}")
    except Exception as e:
        logger.error(f"处理文件 {media_path} 出错: {e}")


if __name__ == '__main__':
    # 单文件处理示例
    media_file = r"D:\Documents\Music\IU-李知恩最好听的.m4a"  # 媒体文件路径
    timeline_file = r"D:\Documents\Music\IU-李知恩最好听的.txt"  # 时间轴文本路径
    output_dir = r""  # 输出目录，可留空自动生成

    # 批量处理目录（放置同名媒体和txt文件）若为空或目录不存在，则只处理单文件
    batch_dir_path = r"D:\Documents\000000"
    # 判断是否批量处理
    if not batch_dir_path or batch_dir_path.strip() == "" or not Path(batch_dir_path).exists():
        split_media_by_timeline(media_file, timeline_file, output_dir)
    else:
        batch_dir = Path(batch_dir_path)
        # 支持多种媒体格式
        for ext in ["*.m4a", "*.aac", "*.mp3", "*.mp4"]:
            for media_path in batch_dir.glob(ext):
                timeline_path = media_path.with_suffix('.txt')
                if timeline_path.exists():
                    split_media_by_timeline(str(media_path), str(timeline_path), "")
